#include "cvector.h"

/**
 * CVector - constructor
 */
template <typename T>
CVector<T>::CVector() {
  this->init(1);
}
//---------------------------------------------------------------------------

/**
 * CVector - constructor, creates empty vector of given size
 * @param size
 */
template <typename T>
CVector<T>::CVector(TIndex size) {
  this->init(size);
}
//---------------------------------------------------------------------------

/**
 * CVector - constructor, creates vector from sequence of given length
 * @param size
 * @param items
 */
template <typename T>
CVector<T>::CVector(TIndex size, T items[]) {
  this->size = size;
  this->createItems();
  for (TIndex i = 0; i < size; i++) this->items[i] = items[i];
}
//---------------------------------------------------------------------------

/**
 * CVector - copy constructor
 * @param v
 */
template <typename T>
CVector<T>::CVector(const CVector<T> &v) {
  this->copyFrom(v);
}
//---------------------------------------------------------------------------

/**
 * CVector - copy constructor
 * @param v
 */
template <typename T>
CVector<T>::CVector(const CVectorBase<T> &v) {
  this->copyFrom(v);
}
//---------------------------------------------------------------------------

/**
 * ~CVector - destructor, free vector from memory
 */
template <typename T>
CVector<T>::~CVector() {
  this->free();
}
//---------------------------------------------------------------------------

/**
 * operator= - assign (copy) vector
 * @param v
 * @return this
 */
template <typename T>
CVector<T>& CVector<T>::operator = (const CVector<T> &v) {
  this->free();
  this->copyFrom(v);
  return *this;
}
//---------------------------------------------------------------------------

/**
 * operator+= - adds given vector to this vector
 * @param v
 * @return this
 */
template <typename T>
CVector<T>& CVector<T>::operator += (const CVector<T> &v) {

  // If sizes of vectors do not match, throw exception
  if (getSize() != v.getSize()) {
    throw CInvalidSizeException(getClassName(), "operator+=");
  }
  return (*this = CVectorBase<T>::operator+=(v));
}
//---------------------------------------------------------------------------

/**
 * operator-= - subtracts given vector from this vector
 * @param v
 * @return this
 */
template <typename T>
CVector<T>& CVector<T>::operator -= (const CVector<T> &v) {

  // If sizes of vectors do not match, throw exception
  if (getSize() != v.getSize()) {
    throw CInvalidSizeException(getClassName(), "operator-=");
  }
  return (*this = CVectorBase<T>::operator-=(v));
}
//---------------------------------------------------------------------------

/**
 * operator+ - sum of vectors
 * @param v
 * @return sum
 */
template <typename T>
CVector<T> CVector<T>::operator + (const CVector<T> &v) const {
  return CVector<T>(*this) += v;
}
//---------------------------------------------------------------------------

/**
 * operator- - difference of vectors
 * @param v
 * @return difference
 */
template <typename T>
CVector<T> CVector<T>::operator - (const CVector<T> &v) const {
  return CVector<T>(*this) -= v;
}
//---------------------------------------------------------------------------

/**
 * operator* - multiplies vector by number
 * @param num
 * @return multiplied vector
 */
template <typename T>
CVector<T> CVector<T>::operator * (T num) const {
  return CVector<T>(*this) *= num;
}
//---------------------------------------------------------------------------

/**
 * operator/ - divides vector by number
 * @param num
 * @return divided vector
 */
template <typename T>
CVector<T> CVector<T>::operator / (T num) const {
  return CVector<T>(*this) /= num;
}
//---------------------------------------------------------------------------

/**
 * getSize - returns size (num of items) of vector
 * @return size of vector
 */
template <typename T>
TIndex CVector<T>::getSize() const {
  return size;
}
//---------------------------------------------------------------------------

/**
 * setSize - sets size (num of items) of vector
 * @param size
 */
template <typename T>
void CVector<T>::setSize(TIndex size) {
  this->size = size;
}
//---------------------------------------------------------------------------

/**
 * minValues - creates vector from minimum items of two vectors
 * @param v1
 * @param v2
 * @return vector of minimum items
 */
template <typename T>
CVector<T> CVector<T>::minValues(const CVector<T> &v1, const CVector<T> &v2) {

  // If sizes of vectors do not match, throw exception
  if (v1.getSize() != v2.getSize()) {
    throw CInvalidSizeException(getClassName(), "minValues");
  }

  // Minimum
  CVector<T> result(v1.getSize());

  // Create minimum vector
  for (TIndex i = 0; i < v1.getSize(); i++) {
    result.set(i, min(v1.get(i), v2.get(i)));
  }
  return result;
}
//---------------------------------------------------------------------------

/**
 * maxValues - creates vector from maximum items of two vectors
 * @param v1
 * @param v2
 * @return vector of maximum items
 */
template <typename T>
CVector<T> CVector<T>::maxValues(const CVector<T> &v1, const CVector<T> &v2) {

  // If sizes of vectors do not match, throw exception
  if (v1.getSize() != v2.getSize()) {
    throw CInvalidSizeException(getClassName(), "maxValues");
  }

  // Maximum
  CVector<T> result(v1.getSize());

  // Create maximum vector
  for (TIndex i = 0; i < v1.getSize(); i++) {
    result.set(i, max(v1.get(i), v2.get(i)));
  }
  return result;
}
//---------------------------------------------------------------------------

/**
 * dot - dot product of two vectors
 * @param v1
 * @param v2
 * @return dot product
 */
template <typename T>
T CVector<T>::dot(const CVector<T> &v1, const CVector<T> &v2) {

  // If sizes of vectors do not match, throw exception
  if (v1.getSize() != v2.getSize()) {
    throw CInvalidSizeException(getClassName(), "dot");
  }
  return CVectorBase<T>::dot(v1, v2);
}
//---------------------------------------------------------------------------

template class CVector<char>;
template class CVector<short>;
template class CVector<int>;
template class CVector<long>;
template class CVector<float>;
template class CVector<double>;
template class CVector<CBigInt>;
template class CVector<CFraction>;
